#ifndef SOUND_H
#define SOUND_H

#include <stdint.h>

#define AUDIO_BUFFER_SIZE 1024
#define AUDIO_CLOCK_RATE 96000
#define NUM_VOICES 3
#define MAX_SOUNDS 16

typedef void (*SubmitAudioCallback)(float* samples, size_t buffer_size, void* userdata);

typedef enum SoundType {
    SOUND_EAT1,
    SOUND_EAT2,
    SOUND_EAT_GHOST,
    SOUND_EAT_FRUIT,
    SOUND_BACKGROUND,
    SOUND_FRIGHTENED,
    SOUND_GHOST_RETURN
} SoundType;

typedef struct Voice {
    unsigned int counter;
    int frequency;
    int waveform;
    float volume;

    float sample;
} Voice;

typedef struct Sound {
    int active;
    int tick;
    SoundType type;

    int voice_index;
    int volume, waveform, frequency;
} Sound;

typedef struct LowPassFilter {
    // a[0] isn't actually used since the other coefficients are already
    // normalized by that value.
    float a[3];
    float b[3];
    float x[3];
    float y[3];
} LowPassFilter;

typedef struct SoundManager {
    float* audio_buffer;
    int buffer_index;
    Voice voices[NUM_VOICES];
    Sound sounds[MAX_SOUNDS];

    // filter for downsampling and also just in general
    // getting rid of those nasty super-high frequencies
    // on certain sounds
    LowPassFilter filter[NUM_VOICES];

    unsigned int time_accum;
    unsigned int clock_time_accum;

    unsigned int sample_rate;
    SubmitAudioCallback submit_audio;
    void* audio_userdata;

    // variables for reading preprocessed
    // audio "dumps"
    // i.e. prelude music, death sound
    const uint32_t* current_dump;
    uint8_t dump_voices;
    size_t dump_index;
    size_t dump_size;
} SoundManager;

/// Initialize a sound manager
extern void sound_init(SoundManager* sound);

/// Dispose a sound manager
extern void sound_free(SoundManager* sound);

/// Update a sound manager
extern void sound_update(SoundManager* sound);

/// Start a sound given the sound type
extern void sound_start(SoundManager* manager, SoundType sound);

/// Stop a sound given the sound type
extern void sound_stop(SoundManager* manager, SoundType sound);

/// Stop all currently playing sounds
extern void sound_stop_all(SoundManager* manager);

/// Start playback of a sound dump
extern void sound_start_dump(SoundManager* manager, uint8_t voices, const uint32_t* dump, size_t size);

#endif